#include "MemoryOpenGL.h"
#pragma comment(lib, "OpenGL32.lib")

// class MemoryOpenGL
MemoryOpenGL::MemoryOpenGL()
{
    memset(&mBitmapInfo, 0, sizeof(mBitmapInfo));
    mWidth      = 0;
    mHeight     = 0;
    mBitCount   = 24;
    mBits       = NULL;
    mBitmap     = NULL;
    mOldBitmap  = NULL;
    mMemoryDC   = NULL;
    mGLContext  = NULL;
}

MemoryOpenGL::~MemoryOpenGL()
{
    finiOpenGL();
}

bool MemoryOpenGL::initOpenGL(int width, int height)
{
    if((mWidth != width) || (mHeight != height) || (mMemoryDC == NULL) || (mBitmap == NULL) || (mGLContext == NULL))
    {
        finiOpenGL();
    }

    if(mGLContext != NULL)
    {
        return true;
    }

    int ret = createMemoryBitmap(width, height);
    if(ret != 0)
    {
        return false;
    }
    ret = initMemoryOpenGL();
    if(ret != 0)
    {
        return false;
    }
    return true;
}

void MemoryOpenGL::finiOpenGL()
{
    if(mGLContext != NULL)
    {
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(mGLContext);
        mGLContext = NULL;
    }

    if(mOldBitmap != NULL)
    {
        SelectObject(mMemoryDC, mOldBitmap);
        mOldBitmap = NULL;
    }
    if(mBitmap != NULL)
    {
        DeleteObject(mBitmap);
        mBitmap = NULL;
    }
    if(mMemoryDC != NULL)
    {
        DeleteObject(mMemoryDC);
        mMemoryDC = NULL;
    }
}

int MemoryOpenGL::createMemoryBitmap(int width, int height)
{
    mWidth  = width;
    mHeight = height;

    mMemoryDC = CreateCompatibleDC(NULL);
    if(mMemoryDC == NULL)
    {
        return -1;
    }

    memset(&mBitmapInfo, 0, sizeof(mBitmapInfo));
    mBitmapInfo.bmiHeader.biSize             = sizeof(BITMAPINFOHEADER);
    mBitmapInfo.bmiHeader.biWidth            = width;
    mBitmapInfo.bmiHeader.biHeight           = height;
    mBitmapInfo.bmiHeader.biPlanes           = 1;
    mBitmapInfo.bmiHeader.biBitCount         = mBitCount;
    mBitmapInfo.bmiHeader.biCompression      = BI_RGB;
    mBitmapInfo.bmiHeader.biSizeImage        = width*height*(mBitCount/8);

    mBitmap = CreateDIBSection(mMemoryDC, &mBitmapInfo, DIB_RGB_COLORS, &mBits, NULL, 0);
    if(mBitmap == NULL)
    {
        return -2;
    }

    mOldBitmap = (HBITMAP)SelectObject(mMemoryDC, mBitmap);

    return 0;
}

int MemoryOpenGL::initMemoryOpenGL()
{
    if(mGLContext != NULL)
    {
        return 0;
    }

    PIXELFORMATDESCRIPTOR pfd = 
    {
        sizeof(PIXELFORMATDESCRIPTOR),  /* size */
        1,                              /* version */
        PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI,
        PFD_TYPE_RGBA,                  /* color type */
        mBitCount,                      /* prefered color depth */
        0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
        0,                              /* no alpha buffer */
        0,                              /* alpha bits (ignored) */
        0,                              /* no accumulation buffer */
        0, 0, 0, 0,                     /* accum bits (ignored) */
        mBitCount,                      /* depth buffer */
        0,                              /* no stencil buffer */
        0,                              /* no auxiliary buffers */
        PFD_MAIN_PLANE,                 /* main layer */
        0,                              /* reserved */
        0, 0, 0,                        /* no layer, visible, damage masks */
    };

    int pixelFormat = ChoosePixelFormat(mMemoryDC, &pfd);
    if(pixelFormat == 0)
    {
        return -1;
    }

    if(!SetPixelFormat(mMemoryDC, pixelFormat, &pfd))
    {
        DWORD dwError = GetLastError();
        return -2;
    }

    mGLContext = wglCreateContext(mMemoryDC);
    if(mGLContext == NULL)
    {
        return -3;
    }

    if(!wglMakeCurrent(mMemoryDC, mGLContext))
    {
        return -4;
    }

    glViewport(0, 0, mWidth, mHeight);

    glEnable(GL_POINT_SMOOTH);
    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    glEnable(GL_POLYGON_SMOOTH);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);

    return 0;
}

int MemoryOpenGL::getWidth()
{
    return mWidth;
}

int MemoryOpenGL::getHeight()
{
    return mHeight;
}

void * MemoryOpenGL::getBits()
{
    return mBits;
}

HDC MemoryOpenGL::getDC()
{
    return mMemoryDC;
}
